package me.hetong.caigou.entity;

import javafx.application.Platform;
import javafx.geometry.Side;
import javafx.geometry.VPos;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.TextAlignment;
import lombok.Data;
import me.hetong.caigou.util.FenUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 棋盘CANVAS
 *
 * @author hetong
 */
@Data
public class ChessboardEdit extends Canvas {

    private GraphicsContext gc;
    private int gridSize = 36;// 每个方格的宽高
    private int gridSizeHalf = gridSize / 2;// 每个方格宽高减半
    private int crossPy = 3;// 十字交叉点偏移量
    private int crossLength = 8;// 十字交叉点线长度
    private int lineWidth = 1;// 默认线宽
    private int outLineWidth = 2;// 棋盘外边框线宽
    private int outLinePy = 4;// 棋盘外边框偏移量
    private String backgroundColor = "#666";
    private Paint backgroundPaint;// 棋盘背景颜色
//    private Image chuheImage = new Image("/image/chessboard/ch1.png");// 楚河图片
//    private Image hanjieImage = new Image("/image/chessboard/hj1.png");// 汉界图片
    private Image ccImage = new Image("image/chessboard/style/default/to.png");// 选中图片
    private Integer py = gridSize / 4;
    private List<Chess> chessList = new ArrayList<>();
    private Map<String, Image> imageMap = new HashMap<>(36);
    private double radius = 16;
    private double radiusHalf = radius / 2;
    private Chess click1;// 当前选择的棋子
    private Chess blank;// 当前选中的空白位置
    private boolean turnRed = true;

    public ChessboardEdit() {
        init();
    }

    public ChessboardEdit(int size) {
        this.gridSize = size;
        init();
    }

    private void initImage() {
        for (Chess chess : chessList) {
            String s = (chess.getType() + chess.getK()).toLowerCase().replace("w", "r");
            String url = "image/chessboard/style/default/" + s + ".png";
            Image image = new Image(url);
            imageMap.put(chess.getType() + chess.getK(), image);
        }
    }

    private void init() {

        this.setWidth(gridSize * 9 + gridSizeHalf);
        this.setHeight(gridSize * 10 + gridSizeHalf);
        this.gc = this.getGraphicsContext2D();

        this.setDefault();

        chessList = FenUtils.fenToChessList(null);
        initImage();

        this.draw();

        this.setOnMouseClicked(event -> {
            if (event.getButton() == MouseButton.SECONDARY) {
//                ChessboardRightMenu.getInstance().show(this, Side.RIGHT, event.getX() - this.widthProperty().doubleValue(), event.getY());
            } else if (event.getButton() == MouseButton.PRIMARY) {
//                ChessboardRightMenu.getInstance().hide();
                leftClick(event);
            }
        });
    }

    private void leftClick(MouseEvent event) {
        int m = (int) (event.getX() - gridSizeHalf) / gridSize;
        int n = (int) (event.getY() - gridSizeHalf) / gridSize;

        Chess c = FenUtils.getChess(chessList, m, n);

        if (c == null) {
            c = new Chess();
            c.setX(m);
            c.setY(n);
            if (click1 == null) {
                this.setBlank(c);
                this.setClick1(null);
            } else {
                // 走子
                step(c);
            }
        } else {
            this.setBlank(null);

            if (click1 == null) {
                this.setClick1(c);
//                    if (turnRed && c.getType().equals("w")) {
//                        UIManager.log("红方走子");
//                    } else if (!turnRed && c.getType().equals("b")) {
//                        this.setClick1(c);
//                        UIManager.log("黑方走子");
//                    } else {
//                        UIManager.log("当前轮到" + turnRed + "走棋");
//                    }
            } else {
                if (click1.equals(c)) {
                    // 点击的是同一个棋子
                    setClick1(null);
                } else {
                    if (click1.getType().equals(c.getType())) {
                        // 点击的是已方棋子
                        setClick1(c);
                    } else {
                        // 点击的是对方棋子,吃子
                        step(c);
                    }
                }
            }
        }

        draw();
    }

    private void step(Chess c) {
        FenUtils.popChess(chessList, c.getX(), c.getY());
        click1.setX(c.getX());
        click1.setY(c.getY());
        this.setBlank(null);
        this.setClick1(null);
    }

    private void setDefault() {
        this.gc.setTextAlign(TextAlignment.CENTER);
        this.gc.setTextBaseline(VPos.CENTER);
        this.gc.setFill(Paint.valueOf("#3d3d3d"));
        this.gc.setStroke(Paint.valueOf("#3d3d3d"));
    }

    public void draw() {
        Platform.runLater(() -> {
            gc.clearRect(0, 0, this.getWidth(), this.getHeight());
            gc.setFill(Color.valueOf(backgroundColor));
            gc.fillRect(0, 0, this.getWidth(), this.getHeight());

            // 画横线
            for (int i = 0; i <= 9; i++) {
                drawLine(0, i, 8, i);
            }

            // 画竖线
            drawLine(0, 0, 0, 9);
            for (int i = 1; i <= 7; i++) {
                drawLine(i, 0, i, 4);
                drawLine(i, 5, i, 9);
            }
            drawLine(8, 0, 8, 9);

            // 画边框粗线
            drawBoardLine();

            // 画斜线叉
            drawLine(3, 0, 5, 2);
            drawLine(5, 0, 3, 2);
            drawLine(3, 7, 5, 9);
            drawLine(5, 7, 3, 9);

            // 画十字
            drawCross4(1, 2);
            drawCross4(7, 2);
            drawCross4(2, 3);
            drawCross4(4, 3);
            drawCross4(6, 3);
            drawCross4(2, 6);
            drawCross4(4, 6);
            drawCross4(6, 6);
            drawCross4(1, 7);
            drawCross4(7, 7);
            drawCross2L(0, 3);
            drawCross2L(0, 6);
            drawCross2R(8, 3);
            drawCross2R(8, 6);

            for (int i = 0; i < 9; i++) {
                drawTextTop(i, String.valueOf(i + 1));
            }

            drawTextBottom(0, "九");
            drawTextBottom(1, "八");
            drawTextBottom(2, "七");
            drawTextBottom(3, "六");
            drawTextBottom(4, "五");
            drawTextBottom(5, "四");
            drawTextBottom(6, "三");
            drawTextBottom(7, "二");
            drawTextBottom(8, "一");

//            gc.drawImage(chuheImage, (this.getWidth() - 50) / 2 - 2.5 * gridSize, (this.getHeight() - 20) / 2, 50, 20);
//            gc.drawImage(hanjieImage, (this.getWidth() - 50) / 2 + 2.5 * gridSize, (this.getHeight() - 20) / 2, 50, 20);

            if (click1 != null) {
                gc.drawImage(ccImage, click1.getX() * gridSize + gridSizeHalf / 2 + 1, click1.getY() * gridSize + gridSizeHalf / 2 + 1, gridSize - 2, gridSize - 2);
                setDefault();
            }

            if (blank != null) {
                gc.drawImage(ccImage, blank.getX() * gridSize + gridSizeHalf / 2 + 1, blank.getY() * gridSize + gridSizeHalf / 2 + 1, gridSize - 2, gridSize - 2);
                setDefault();
            }

            for (Chess li : chessList) {
                Image image = imageMap.get(li.getType() + li.getK());
                gc.drawImage(image, li.getX() * gridSize + (gridSizeHalf / 2), li.getY() * gridSize + gridSizeHalf / 2, gridSize, gridSize);
            }
        });
    }

    private void drawEngiZhao(Zhao zhao, String color, String number) {
        double fromX = (zhao.getX1() * gridSize + gridSizeHalf * 1.5);
        double fromY = (zhao.getY1() * gridSize + gridSizeHalf * 1.5);
        double toX = (zhao.getX2() * gridSize + gridSizeHalf * 1.5);
        double toY = (zhao.getY2() * gridSize + gridSizeHalf * 1.5);
        color += "bb";
        drawLineArrow2(fromX, fromY, toX, toY, color);
        drawCircleNum(fromX, toX, fromY, toY, number);
    }

    private void drawCircleNum(double fromX, double toX, double fromY, double toY, String text) {
        double cx = (fromX + toX) / 2;
        double cy = (fromY + toY) / 2;
        gc.setFill(Paint.valueOf("#fff"));
        gc.fillOval(cx - radiusHalf, cy - radiusHalf, radius, radius);
        setDefault();
        gc.fillText(text, cx, cy);
    }

    /**
     * 画直线
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     */
    private void drawLine(int x1, int y1, int x2, int y2) {
        gc.strokeLine(x1 * gridSize + gridSizeHalf * 1.5, y1 * gridSize + gridSizeHalf * 1.5, x2 * gridSize + gridSizeHalf * 1.5, y2 * gridSize + gridSizeHalf * 1.5);
    }

    /**
     * 画棋盘十字
     *
     * @param x
     * @param y
     */
    private void drawCross4(int x, int y) {
        drawCross2L(x, y);
        drawCross2R(x, y);
    }

    /**
     * 画棋盘左半边十字
     *
     * @param x
     * @param y
     */
    private void drawCross2L(int x, int y) {
        // 中心点
        x = x * gridSize + gridSizeHalf + gridSizeHalf / 2;
        y = y * gridSize + gridSizeHalf + gridSizeHalf / 2;

        // 右上
        gc.strokeLine(x + crossPy, y - crossPy, x + crossPy + crossLength, y - crossPy);
        gc.strokeLine(x + crossPy, y - crossPy, x + crossPy, y - crossPy - crossLength);
        // 右下
        gc.strokeLine(x + crossPy, y + crossPy, x + crossPy + crossLength, y + crossPy);
        gc.strokeLine(x + crossPy, y + crossPy, x + crossPy, y + crossPy + crossLength);
    }

    /**
     * 画棋盘右半边十字
     *
     * @param x
     * @param y
     */
    private void drawCross2R(int x, int y) {
        // 中心点
        x = x * gridSize + gridSizeHalf + gridSizeHalf / 2;
        y = y * gridSize + gridSizeHalf + gridSizeHalf / 2;
        // 左上
        gc.strokeLine(x - crossPy, y - crossPy, x - crossPy - crossLength, y - crossPy);
        gc.strokeLine(x - crossPy, y - crossPy, x - crossPy, y - crossPy - crossLength);
        // 左下
        gc.strokeLine(x - crossPy, y + crossPy, x - crossPy - crossLength, y + crossPy);
        gc.strokeLine(x - crossPy, y + crossPy, x - crossPy, y + crossPy + crossLength);
    }

    private void drawTextTop(int x, String text) {
        gc.setFill(Color.valueOf("#3d3d3d"));
        gc.fillText(text, x * gridSize + gridSizeHalf * 1.5, 0 * gridSize + gridSizeHalf * 1.5 - 15);
    }

    private void drawTextBottom(int x, String text) {
        gc.fillText(text, x * gridSize + gridSizeHalf * 1.5, 9 * gridSize + gridSizeHalf * 1.5 + 15);
    }

    private void drawBoardLine() {
        gc.setLineWidth(outLineWidth);
        gc.strokeLine(0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 8 * gridSize + gridSizeHalf * 1.5 + outLinePy, 0 * gridSize + gridSizeHalf * 1.5 - outLinePy);
        gc.strokeLine(0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 9 * gridSize + gridSizeHalf * 1.5 + outLinePy);
        gc.strokeLine(0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 9 * gridSize + gridSizeHalf * 1.5 + outLinePy, 8 * gridSize + gridSizeHalf * 1.5 + outLinePy, 9 * gridSize + gridSizeHalf * 1.5 + outLinePy);
        gc.strokeLine(8 * gridSize + gridSizeHalf * 1.5 + outLinePy, 0 * gridSize + gridSizeHalf * 1.5 - outLinePy, 8 * gridSize + gridSizeHalf * 1.5 + outLinePy, 9 * gridSize + gridSizeHalf * 1.5 + outLinePy);
        gc.setLineWidth(lineWidth);
    }

    private void drawArrow(double fromX, double fromY, double toX, double toY, String color) {

        int theta = 30;
        int headlen = 10;
        int width = 3;

        // 计算各角度和对应的P2,P3坐标
        double angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,
                angle1 = (angle + theta) * Math.PI / 180,
                angle2 = (angle - theta) * Math.PI / 180,
                topX = headlen * Math.cos(angle1),
                topY = headlen * Math.sin(angle1),
                botX = headlen * Math.cos(angle2),
                botY = headlen * Math.sin(angle2);

        gc.save();
        gc.beginPath();

        double arrowX = fromX - topX;
        double arrowY = fromY - topY;

        gc.moveTo(arrowX, arrowY);
        gc.moveTo(fromX, fromY);
        gc.lineTo(toX, toY);
        arrowX = toX + topX;
        arrowY = toY + topY;
        gc.moveTo(arrowX, arrowY);
        gc.lineTo(toX, toY);
        arrowX = toX + botX;
        arrowY = toY + botY;
        gc.lineTo(arrowX, arrowY);
        gc.setStroke(Paint.valueOf(color));
        gc.setLineWidth(width);
        gc.stroke();
        gc.restore();
    }

    public void setClick1(Chess click1) {
        this.click1 = click1;
        draw();
    }

    public void setBlank(Chess blank) {
        this.blank = blank;
        draw();
    }

    public void setChessList(List<Chess> chessList) {
        if (chessList == null) {
            this.chessList = FenUtils.fenToChessList(null);
        } else {
            this.chessList = chessList;
        }
    }

    public void setChessList(String fen) {
        this.chessList = FenUtils.fenToChessList(fen);
        draw();
    }

    /**
     * @param {*canvas context 对象} ctx
     * @param {*起点横坐标} fromX
     * @param {*起点纵坐标} fromY
     * @param {*终点横坐标} toX
     * @param {*终点纵坐标} toY
     *                 以下注释以终点在坐标第一象限内，且方向为右上方
     */
    private void drawLineArrow2(double fromX, double fromY, double toX, double toY, String color) {
        double headlen = (0.2 * 1.41 * Math.sqrt((fromX - toX) * (fromX - toX) + (fromY - toY) * (fromY - toY)));//箭头头部长度
        headlen = headlen > 40 ? 40 : headlen;//40是箭头头部最大值
        double theta = 30;//自定义箭头线与直线的夹角
        double arrowX, arrowY;//箭头线终点坐标
        // 计算各角度和对应的箭头终点坐标
        double angle = (Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI);
        double angle1 = ((angle + theta) * Math.PI / 180);
        double angle2 = ((angle - theta) * Math.PI / 180);
        double topX = (headlen * Math.cos(angle1));
        double topY = (headlen * Math.sin(angle1));
        double botX = (headlen * Math.cos(angle2));
        double botY = (headlen * Math.sin(angle2));
        boolean toLeft = fromX > toX;
        boolean toUp = fromY > toY;

        //箭头最上点
        arrowX = toX + topX;
        arrowY = toY + topY;
        //箭头下拐点
        double arrowX1 = toX + botX;
        double arrowY1 = toY + botY;
        //箭头上拐点
        double arrowX2 = (toUp ? arrowX + 0.25 * Math.abs(arrowX1 - arrowX) : arrowX - 0.25 * Math.abs(arrowX1 - arrowX));
        double arrowY2 = (toLeft ? arrowY - 0.25 * Math.abs(arrowY1 - arrowY) : arrowY + 0.25 * Math.abs(arrowY1 - arrowY));
        //箭头最下点 
        double arrowX3 = (toUp ? arrowX + 0.75 * Math.abs(arrowX1 - arrowX) : arrowX - 0.75 * Math.abs(arrowX1 - arrowX));
        double arrowY3 = (toLeft ? arrowY - 0.75 * Math.abs(arrowY1 - arrowY) : arrowY + 0.75 * Math.abs(arrowY1 - arrowY));

        gc.beginPath();
        //起点-起点，闭合
        gc.moveTo(fromX, fromY);
        gc.lineTo(arrowX2, arrowY2);
        gc.lineTo(arrowX, arrowY);
        gc.lineTo(toX, toY);

        gc.lineTo(arrowX1, arrowY1);
        gc.lineTo(arrowX3, arrowY3);
        gc.lineTo(fromX, fromY);
        gc.closePath();
        gc.setFill(Paint.valueOf(color));
        gc.setStroke(Paint.valueOf("#ffffff00"));
        gc.fill();
//        gc.stroke();

        setDefault();
    }
}